/**
 * Copyright 2018 人人开源 http://www.renren.io
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.freeter.interceptor;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.freeter.common.utils.RedisUtils;
import com.freeter.modules.gjs.entity.User;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.freeter.annotation.Login;
import com.freeter.common.exception.RRException;
import com.freeter.common.utils.JwtUtils;

import io.jsonwebtoken.Claims;

import java.util.Date;

/**
 * 权限(Token)验证
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2017-03-23 15:38
 */
@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtils redisUtils;

    public static final String USER_KEY = "userId";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        Login annotation = null;
        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(Login.class);
         }

        if(null == annotation){
            return true;
        }

        //获取用户凭证
         String token = request.getHeader(jwtUtils.getHeader());
        if(StringUtils.isBlank(token)){
            token = request.getParameter(jwtUtils.getHeader());
        }
        if(StringUtils.isBlank(token)){
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie c : cookies) {
                    if (jwtUtils.getHeader().equals(c.getName())) {
                        token = c.getValue();
                        break;
                    }
                }
            }
        }
        if(StringUtils.isBlank(token)){
            throw new RRException("错误001,无效token,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }

        Claims claims = null;
        try {
            claims = jwtUtils.getClaimByToken(token);
        }catch (Exception e){  }
        if(claims == null ){
            throw new RRException("错误002,无效token,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }

        //设置userId到request里，后续根据userId，获取用户信息
        User loginUsr = null;
        try {
            String subject = claims.getSubject();
            loginUsr = JSONObject.parseObject(subject, User.class);
        }catch (Exception e){
            throw new RRException("错误003,无效token,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }
        request.setAttribute(USER_KEY, loginUsr.getId());
        request.setAttribute("LOGIN_USER", loginUsr.getLogin());
        String cachToken = redisUtils.get(loginUsr.getId() + "_loginToken");
        //token 的用户在别的地方登录
        if(StringUtils.isEmpty(cachToken) ){
            throw new RRException("错误004,无效token,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }
        if( !token.equals(cachToken)){
            throw new RRException("错误005,无效token,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }
        //判断时效性
        String expDateStr = redisUtils.get(token+"_loginToken_exp");
        if(StringUtils.isEmpty(expDateStr)){
            throw new RRException("错误006,无效token,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }
        DateTime expDate = DateUtil.parse(expDateStr, DatePattern.PURE_DATETIME_MS_FORMAT);
        Date now = new Date();
        if(now.after(expDate)){
            throw new RRException("错误007,token过期,请重新登录",HttpStatus.UNAUTHORIZED.value());
        }
        redisUtils.set(token+"_loginToken_exp", DateUtil.format(jwtUtils.getExpDate(), DatePattern.PURE_DATETIME_MS_FORMAT));
        return true;
    }
}
